#include "FileDataStream.h"
#include <iostream>

using namespace Huffman;

FileDataStream::FileDataStream(std::string filePath, OpenMode openMode)
{
	std::ios_base::openmode mode = openMode == Read ? std::fstream::in : std::fstream::out;
	bufferIndex = openMode == Read ? -1 : 7; /*TODO domyslna wartosc nie moze byc dobra jednoczesnie dla kodera i dekodera */
	this -> stream = new std::fstream(filePath, mode);
}

FileDataStream::~FileDataStream(void)
{
	// empty destructor
}

char FileDataStream::read() {	

	std::bitset<8> byteBuffer = 0;

	for(int i = 7; i >= 0; i--) {
		byteBuffer[i] = readBit();
	}	
	return (char) byteBuffer.to_ulong();
}


void FileDataStream::writeEncodedSymbol(EncodedSymbol* symbol) {

	// writes the single bits of the data
	std::bitset<8> byteBuffer = (char) symbol -> getValue();

	for(int i = 0 ; i <= symbol -> getLenght()-1; i++) {
		writeBit(byteBuffer[i]);
	}


}

void FileDataStream::write(char data) {

	// writes the single bits of the data
	std::bitset<8> byteBuffer = data;

	for(int i = 7; i >= 0; i--) {
		writeBit(byteBuffer[i]);
	}
}

bool FileDataStream::readBit()
{
	if(bufferIndex < 0) 
	{
		readBuffer();
	}
	
	return buffer[bufferIndex--];
}

void FileDataStream::writeBit(bool bit)
{
	if(bufferIndex < 0) {
		writeBuffer();
	}

	buffer[bufferIndex--] = bit;
}

bool FileDataStream::isEof() {
	return stream -> eof();
}

void FileDataStream::flush() 
{
	// TODO the flush should be used only for writing
	writeBuffer();
}

void FileDataStream::writeBuffer() 
{
	stream -> put((char)buffer.to_ulong());

	buffer = 0;
	bufferIndex = bufferSize - 1;
}

void FileDataStream::readBuffer() 
{
	int c = stream -> get();

	buffer = c;
	bufferIndex = bufferSize - 1;
}

void FileDataStream::close() 
{
	stream -> flush();
	stream -> close();
}